(function($){
function create(tagName, className, parent, innerHtml){
    var e = document.createElement(tagName);
    if(!!className){
        e.className = className;
    }
    if(!!parent){
        parent.appendChild(e);
    }
    if(!!innerHtml){
        e.innerHTML = innerHtml;
    }
    return e;
}
function groupBy(list, key){
    if(!list || !list.length){
        return {};
    }
    var map = {};
    for(var i = 0; i < list.length; i++){
        var item = list[i];
        var k = item[key];
        if(!map[k]){
            map[k] = [];
        }
        map[k].push(item);
    }
    return map;
}
function getSelectShownText(select){
    var jOp = get$SelectOption(select);
    return jOp.val()? jOp.html(): "";
}
function get$SelectOption(select){
    var j1 = $(select).find("option[selected='selected']");
    var j2 = $(select).find("option[value='"+select.value+"']");
    return j1.length || !j2.length? j1: j2;
}
function setElementData(e, datas){
    for(var k in datas){
        e.dataset[k] = datas[k];
    }
}
$.fn.materialDecomposition = function(buildingList, products, materials, units, btnEl, READ_MODE){
    var __jqThis = this;
    __jqThis.debug = window.DEBUG_MODE || false;
    var TYPE_BUILDING = 0;
    var TYPE_PRODUCT = 1;
    var TYPE_MATERIAL = 2;
    var PM_TYPE_PRODUCT = 0;
    var PM_TYPE_MATERIAL = 1;
    var PM_TYPE_UNIT = 2;
    var PM_LIST_MAP = {};
    var PM_ID_KEY_MAP = {};
    var notifyMsg = NOTIFY_MSG || alert;
    var scopeid = 1;
    var productid = 1;
    var materialid = 1;
    PM_LIST_MAP[PM_TYPE_PRODUCT] = products || [];
    PM_LIST_MAP[PM_TYPE_MATERIAL] = materials || [];
    var PRODUCT_ID_NAME_MAP = iUtils.toKVMap(products, "id", function(e){return e["name"] + "(" + e["sn"] + ")"});
    var MATERIAL_MAP = iUtils.toKVMap(materials, "id", function(e){return {stuff: e["stuff_cn"], name: e["name"] + "(" + e["sn"] + ")"}});
    var UNIT_ID_NAME_MAP = iUtils.toKVMap(units, "id", "name");
    PM_LIST_MAP[PM_TYPE_UNIT] = units || [];
    PM_ID_KEY_MAP[PM_TYPE_PRODUCT] = "pmid";
    PM_ID_KEY_MAP[PM_TYPE_MATERIAL] = "materialid";
    PM_ID_KEY_MAP[PM_TYPE_UNIT] = "id";
    var BTN_TYPE_CN = {};
    BTN_TYPE_CN[TYPE_PRODUCT] = "äº§å";
    BTN_TYPE_CN[TYPE_MATERIAL] = "ç©æ";
    __jqThis.debug && console.log(PM_LIST_MAP);
    $(btnEl).on("click", function(){
       add(null, TYPE_BUILDING).render();
    })
    this.getProductNameById = function(id){
    	return PRODUCT_ID_NAME_MAP[parseInt(id)] || "";
    }
    this.getMaterialNameById = function(id){
    	var m = MATERIAL_MAP[parseInt(id)];
    	return m && m.name || "";
    }
    function formatList(scopeInfo){
        if(!scopeInfo || !scopeInfo.buildingList || !scopeInfo.buildingList.length){
            return [];
        }
        var scopeInfo = JSON.parse(JSON.stringify(scopeInfo));
        var materialMap = groupBy(scopeInfo.materialList, "jobid");
        var productMap = groupBy(scopeInfo.productList, "scopeid");
        for(var i = 0; i < scopeInfo.buildingList.length; i++){
            var b = scopeInfo.buildingList[i];
            var pl = productMap[b.id];
            if(!!pl && !!pl.length){
                b.productList = pl;
                for(var j = 0; j < pl.length; j++){
                    pl[j].materialList = materialMap[pl[j].id];
                }
            }
        }
        return scopeInfo.buildingList;
    }
    
    function getMRow(material, scopeid, productid){
    	//è·åç©æè¡
        var tr = create("tr", "scope-" + scopeid + " product-" + productid + " material-" +materialid);

    	var m1 = MATERIAL_MAP[material.expectmaterialid];
    	var m2 = MATERIAL_MAP[material.materialid];
        if(READ_MODE){
        	tr.appendChild($("<td>"+(m1 && m1.name || "")+"</td>")[0])
        	tr.appendChild($("<td "+(material.materialid && material.expectmaterialid &&  (material.materialid != material.expectmaterialid)? "style='color: red;'": "")+">"+(m2 && m2.name || "")+"</td>")[0])
        	tr.appendChild($("<td>"+(m2 && m2.stuff || "")+"</td>")[0])
        }else {
//            var expectMaterialSelect = getPmSelect(PM_TYPE_MATERIAL, material.expectmaterialid);
            var expectMaterialTd = create("td", "func-td material-expect-select-td lazy-selectpicker-container", tr, "<span class='temp-txt' data-temp-id='"+(material.expectmaterialid || "")+"'>" + (m1 && m1.name || "") + "</span>");
            expectMaterialTd.dataset.id = material.id || "";
            expectMaterialTd.dataset.pmType = PM_TYPE_MATERIAL;
            expectMaterialTd.dataset.objectId = material.expectmaterialid || "";
//            expectMaterialTd.appendChild(expectMaterialSelect);
//            selectPicker(expectMaterialSelect, expectMaterialTd);
            setRemoveBtn(expectMaterialTd, TYPE_MATERIAL, scopeid, productid, materialid);

            //å¾çº¸ä¼å®¡ä¿®æ¹åææè§æ ¼ååå·
//            var materialSelect = getPmSelect(PM_TYPE_MATERIAL, material.materialid, true);
            var materialTd = create("td", "func-td material-select-td lazy-selectpicker-container", tr, "<span "+(material.materialid && material.expectmaterialid &&  (material.materialid != material.expectmaterialid)? "style='color: red;'": "")+" class='temp-txt' data-temp-id='"+(material.materialid || "")+"'>" + (m2 && m2.name || "") + "</span>");
            materialTd.dataset.pmType = PM_TYPE_MATERIAL;
            materialTd.dataset.objectId = material.materialid || "";
            materialTd.dataset.linkage = true;
//            materialTd.appendChild(materialSelect);
//            selectPicker(materialSelect, materialTd);
            //æè´¨	
            var stuffTd = create("td", "");
            stuffTd.innerHTML = "<span class='read-txt stuff-span'>" + (m2 && m2.stuff || "") + "</span>";
            tr.appendChild(stuffTd);
        }
        
        //å¤æ³¨

        var markTd = create("td", "mark-input-td", tr, "<span class='read-mode-element read-txt'>" + (material.mark || "") + "</span>");
        setInput(markTd, "è¯·è¾å¥å¤æ³¨", {dataType: "txt"});
        materialid++;
        return tr;
    }
    function getPRowWithWrapper(product, scopeid){
    	//è·åäº§åè¡ è·åææç©æè¡ï¼å¨ç¬¬ä¸ä¸ªç©æè¡å ä¸äº§åè¡
    	iUtils.check(product.materialList.length, "å¿é¡»æç©æè¡");
    	var wrapper = create("table");
    	var firstMRow;
    	for(var i = 0; i < product.materialList.length; i++){
    		var tr = getMRow(product.materialList[i], scopeid, productid);
    		wrapper.appendChild(tr);
    		if(i == 0){
    			firstMRow = tr;
    		}
    	}
    	var productTd;
    	var p = PRODUCT_ID_NAME_MAP[product.pmid];
        if(READ_MODE){
        	productTd = $("<td>" + (p || "") + "</td>")[0];
        }else {
//        	var select = getPmSelect(PM_TYPE_PRODUCT, product.pmid);
            productTd = create("td", "func-td product-select-td product-series-td lazy-selectpicker-container", "", "<span class='temp-txt' data-temp-id='"+(product.pmid || "")+"'>" + (p || "") + "</span>");
            productTd.dataset.id = product.id || "";
            productTd.dataset.pmType = PM_TYPE_PRODUCT;
            productTd.dataset.objectId = product.pmid || "";
//            productTd.appendChild(select);

//            selectPicker(select, productTd);
            setComponent(productTd, TYPE_MATERIAL, scopeid, productid);
            setRemoveBtn(productTd, TYPE_PRODUCT, scopeid, productid)
        }

        //å·¥ç¨é
        var qtyTd = create("td", "product-qty-input-td product-series-td", "", "<span class='read-mode-element read-txt'>" + (product.qty || "") + "</span>");
        setInput(qtyTd, "è¯·è¾å¥å·¥ç¨é", {dataType: "number"});
        //åä½
//        var unitSelect = getPmSelect(PM_TYPE_UNIT, product.unitid);
        var unitTd = create("td", "product-unit-select-td product-series-td lazy-selectpicker-container", "", "<span class='temp-txt' data-temp-id='"+(product.unitid || "")+"'>" + (UNIT_ID_NAME_MAP[product.unitid] || "") + "</span>");
        
//        selectPicker(unitSelect, unitTd);
        unitTd.dataset.pmType = PM_TYPE_UNIT;
        unitTd.dataset.objectId = product.unitid;
        setElementData(unitTd, {id: product.unitid})
//        unitTd.appendChild(unitSelect);
    	
        iUtils.each.call([unitTd, qtyTd, productTd], function(e){
        	e.setAttribute("rowspan", product.materialList.length);
        	$(firstMRow).attr("data-is-product-row", "1").prepend(e);
        })
        productid++;
        return wrapper;
    }
    function getBRowWithWrapper(building){
    	//è·åæ¥¼æ è¡
    	iUtils.check(building.productList.length, "å¿é¡»æç©æè¡");
    	var wrapper = create("table");
    	var firstMRow;
    	var mRowCount = 0;
    	for(var i = 0; i < building.productList.length; i++){
    		var w = getPRowWithWrapper(building.productList[i], scopeid);
    		var $w = $(w);
    		var trs = $w.find("tr");
    		for(var j = 0; j < trs.length; j++){
    			wrapper.appendChild(trs[j]);
    			mRowCount += 1;
        		if(i == 0 && j == 0){
        			firstMRow = trs[j];
        		}
    		}
    	}
        buildingTd = create("td", "func-td scopename-input-td", "", "<span class='read-mode-element read-txt'>" + (building.scopename || "") + "</span>");
        buildingTd.dataset.id = building.id || "";
        setInput(buildingTd, "è¯·è¾å¥æ¥¼æ å", {dataType: "txt"});

        setComponent(buildingTd, TYPE_PRODUCT, scopeid);
        setRemoveBtn(buildingTd, TYPE_BUILDING, scopeid)
        
        buildingTd.setAttribute("rowspan", mRowCount);
        
        $(firstMRow).attr("data-is-building-row", "1").prepend(buildingTd)
        scopeid++;
        return wrapper;
    }

    function setInput(td, placeholder, datas){
        var input = create("input", " write-mode-element", td);
        setElementData(input, datas)
        input.setAttribute("placeholder", placeholder);
        input.value = td.innerText;
        td.onclick = function(){
            input.focus();
        }
    }
    function selectPicker(select, td){
    	/*select = $(select);
//    	select.data("klajsdflskajf", false);
    	$(td).unbind().on("mouseover", function(){
    		select.selectpicker("refresh");
    		$(this).unbind("mouseover").find(".temp-txt").remove();
    	}).on("click", function(){
//            $(select).data("klajsdflskajf", !$(select).data("klajsdflskajf"));
//            if(!$(select).data("klajsdflskajf")){
//                return false;
//            }
//            $(select).selectpicker('show');
        })*/
        
    }

    function getPmSelect(type, value, linkage){
        var selectDom = create("select");
       
        var option = create("option");
        selectDom.appendChild(option);
        selectDom.className = "selectpicker material-decomposition-select write-mode-element " + (linkage? "linkage": "");
        selectDom.setAttribute("data-live-search", true)
        option.value = "";
        option.innerText = "è¯·éæ©";
        var list = PM_LIST_MAP[type];
        for(var i = 0; i < list.length; i++){
            var item = list[i];
            option = create("option");
            if(value == item.id){
                option.setAttribute("selected", "selected");
            }
            option.value = item.id;
            option.innerText = item.name + (!!item.sn?"(" + item.sn + ")":"");
            selectDom.appendChild(option);
            if(linkage){
                option.dataset.stuff_CN = item.stuff_cn;
            }
        }
        return selectDom;
    }

    function setComponent(td, type, scopeid, productid, materialid){
        var position = td.style.position;
        if(!position){
            td.style.position = "relative";
        }
        var btn = create("span");
        td.appendChild(btn);
        btn.className = "btn composition-btn composition-btn-add write-mode-element " + (type==TYPE_PRODUCT? "composition-btn-1 composition-btn-product": "composition-btn-2");
        btn.innerHTML = "<i class='glyphicon glyphicon-plus'></i>";
        btn.dataset.pmType = type;
        btn.dataset.scopeid = scopeid;
        btn.dataset.productid = productid;
        btn.dataset.materialid = materialid;
    }

    function setRemoveBtn(td, type, scopeid, productid, materialid){//index + 1
        var position = td.style.position;
        if(!position){
            td.style.position = "relative";
        }
        var btn = create("span", "btn composition-btn composition-btn-remove write-mode-element");
        td.appendChild(btn);
        btn.innerHTML = "<i class='glyphicon glyphicon-minus'></i>";
        btn.dataset.pmType = type;
        btn.dataset.scopeid = scopeid;
        btn.dataset.productid = productid;
        btn.dataset.materialid = materialid;
        return btn;
    }

    function getBuildingList(){
        var jqTrs = __jqThis.children();
        var buildingList = [];
        var building;
        var product;
        jqTrs.each(function(){
            var jqThis = $(this);
            var scopenameInputTd = jqThis.find(".scopename-input-td");
            var productSelectTd = jqThis.find(".product-select-td");
            var productQtyInputTd = jqThis.find(".product-qty-input-td");
            var productUnitSelectTd = jqThis.find(".product-unit-select-td");
            var materialExpectSelectTd = jqThis.find(".material-expect-select-td");
            var materialSelectTd = jqThis.find(".material-select-td");
            var markTd = jqThis.find(".mark-input-td");
            if(scopenameInputTd.length > 0){
                //æ¥¼æ 
                building = {id: scopenameInputTd[0].dataset.id, scopename: scopenameInputTd.eq(0).find("input").val(), productList: []};
                buildingList.push(building);
            }
            if(productSelectTd.length > 0){
                //äº§å
                product = {id: productSelectTd.attr("data-id")
                		    , pmid: productSelectTd.find("select").val() || productSelectTd.find(".temp-txt").data("tempId") || ""
                            , qty: productQtyInputTd.find("input").val()
                            , unitid: productUnitSelectTd.find("select").val() || productUnitSelectTd.find(".temp-txt").data("tempId") || ""
                            , materialList: []
                          };
                building.productList.push(product);
            }
            var material = {
                                id: materialExpectSelectTd.attr("data-id") || ""
                                , expectmaterialid: materialExpectSelectTd.find("select").val() || materialExpectSelectTd.find(".temp-txt").data("tempId") || ""
                                , materialid: materialSelectTd.find("select").val() || materialSelectTd.find(".temp-txt").data("tempId") || ""
                                , mark: markTd.find("input").val()
                           }
            product.materialList.push(material);
        })
        return buildingList;
    }

    function add(btn, type){
        if(type == 0){
            //æ·»å æ¥¼æ 
        	var building = {productList: [{materialList: [{}]}]};
        	__jqThis.append(getBRowWithWrapper(building).innerHTML);
        }else {
            var i = btn.dataset.scopeid;
            var j = btn.dataset.productid;
            if(type == 1){
                //æ·»å äº§å
            	var product = {materialList:[{}]};
            	//æ¥¼æ tdçrowspanè¦ + 1
            	__jqThis.find(".scope-" + i+" .scopename-input-td").attr("rowspan", $(".scope-" + i).length + 1)
            	__jqThis.find(".scope-" + i + ":last").after(getPRowWithWrapper(product, i).innerHTML);
            }else {
                //æ·»å ææ
                var material = {};
                //äº§ååæ¥¼æ çrowspanè¦ +1
            	__jqThis.find(".scope-" + i+" .scopename-input-td").attr("rowspan", $(".scope-" + i).length + 1)
            	__jqThis.find(".scope-" + i+".product-" + j+" .product-series-td").attr("rowspan", $(".scope-" + i + ".product-" + j).length + 1)
            	__jqThis.find(".scope-" + i + ".product-" + j + ":last").after(getMRow(material, i, j));
            }
        }
        return __jqThis;
    }
    function materialDiff(expectTd, realTd){
    	var expectSelect = expectTd.find("select");
    	var realSelect = realTd.find("select");
    	var expectTemp = expectTd.find(".temp-txt");
    	var realTemp = realTd.find(".temp-txt");
    	var expect = expectTemp.length? expectTemp.data("tempId"): expectSelect.val();
    	var real = realTemp.length? realTemp.data("tempId"): realSelect.val();
    	//åè²
    	if(real && expect && real != expect){
    		if(realSelect.length){
    			realSelect.siblings("button").css("color", "red");
    		}else {
    			realTemp.css("color", "red");
    		}
    	}else {
    		if(realSelect.length){
    			realSelect.siblings("button").css("color", "");
    		}else {
    			realTemp.css("color", "");
    		}
    	}
    }
    function render(){
    	console.log("table changed")
    	if(!READ_MODE){
	        $(".lazy-selectpicker-container:not(.inited)").unbind().on("mouseover", function(){
	        	var jqThis = $(this).addClass("inited").unbind("mouseover");
	        	var linkage = jqThis.data("linkage");
	        	var pmType = jqThis.data("pmType");
	        	var objectId = jqThis.data("objectId");
	        	var select = getPmSelect(pmType, objectId, linkage);
	        	if(linkage){
	        		$(select).on("change", function(){
	        			var jqThis = $(this);
	        			jqThis.parents("tr").find(".stuff-span").text($(this).find("option:selected").data("stuff_CN"))
	        			materialDiff(jqThis.parents("td").prev(), jqThis.parents("td"))
	            	}).on("refreshed.bs.select", function(){
	            		var jqThis = $(this);
	        			materialDiff(jqThis.parents("td").prev(), jqThis.parents("td"))
	            	})
	        	}
	        	if(jqThis.hasClass("material-expect-select-td")){
	        		$(select).on("change", function(){
	        			var jqThis = $(this);
	        			materialDiff(jqThis.parents("td"), jqThis.parents("td").next())
	        		})
	        	}
	        	jqThis.append(select).find(".selectpicker").selectpicker("refresh");
	        	jqThis.find(".temp-txt").remove();
	        })
    	}
        $(".composition-btn-add").unbind().on("click", function(event){
            event.stopPropagation();
        	var pmType = this.dataset.pmType;
        	add(this, pmType).render();
        })
        $(".composition-btn-remove").unbind().on("click", function(event){
            event.stopPropagation();
        	var type = this.dataset.pmType;
        	var i = this.dataset.scopeid;
        	var j = this.dataset.productid;
        	var k = this.dataset.materialid;
            if(type == TYPE_BUILDING){
                $(".scope-" + i).remove();
            }else {
                if(type == TYPE_PRODUCT){
                	var productRow = $(".scope-" + i + "[data-is-product-row]");
                    if(productRow.length <= 1){
                        notifyMsg("æå°ä¿çä¸ä¸ª");
                        return;
                    }
                    var selectRows = $(".scope-" + i + ".product-" + j);
                    //äº§åä¸­æ¯å¦åå«æ¥¼æ 
                    var firstRow = selectRows.first();
                    var scopeTd = null;
                    if(firstRow.attr("data-is-building-row")){//æ¯æ¥¼æ è¡
                    	scopeTd = firstRow.find("td:first");
                    	selectRows.last().next().prepend(scopeTd);
                    }
                    //å é¤äº§åè¡
                    selectRows.remove();
                    $(".scope-" + i + "[data-is-building-row]").find("td:first").attr("rowspan", $(".scope-" + i).length);
                }else {
                	//äº§åçç©æè¡
                    var materialRow = $(".scope-" + i + ".product-" + j);
                    if(materialRow.length <= 1){
                    	notifyMsg("æå°ä¿çä¸ä¸ª");
                    	return;
                    }
                    var selectRow = $(".scope-" + i + ".product-" + j + ".material-" + k);
                    if(selectRow.attr("data-is-product-row")){
                    	var nextRow = selectRow.next();
                    	nextRow.prepend(selectRow.find(".product-series-td"));
                    	nextRow.attr("data-is-product-row", "1");
                    	if(selectRow.attr("data-is-building-row")){
                        	nextRow.attr("data-is-building-row", "1")
                        	nextRow.prepend(selectRow.find("td:first"));
                    	}
                    }
                    selectRow.remove();

                    $(".scope-" + i + ".product-" + j + "[data-is-product-row]").find(".product-series-td").attr("rowspan",$(".scope-" + i+ ".product-" + j).length)
                	$(".scope-" + i + "[data-is-building-row]").find("td:first").attr("rowspan",$(".scope-" + i).length);
                }
            }
            __jqThis.render();
        })
        return __jqThis;
    }

    function apply(){
        buildingList = getBuildingList();
        return __jqThis;
    }

    function toggleMode(){
        apply().render();
        __jqThis.toggleClass("composition-read-mode");
        __jqThis.toggleClass("composition-write-mode");
    }

    function reset(){
        buildingList = [];
    }

    function applyBuildingList(bl){
        buildingList = bl;
        __jqThis.empty();
        for(var i = 0; i < buildingList.length; i++){
            var building = buildingList[i];
            var wrapper = getBRowWithWrapper(building, i);
            var trs = $(wrapper).find("tr");
            for(var j = 0; j < trs.length; j++){
            	__jqThis.append(trs[j]);
            }
        }
        return render();
    }

    function applyExcelData(data){
        var bl = [];
        var buildingMap = {};
        var productMap = {};
        for(var k in data){
            var d = data[k];
            var b = buildingMap[d.buildingNo];
            if(!b){
                b = {productList:[],scopename: d.scopename}
                buildingMap[d.buildingNo] = b;
                bl.push(b);
            }
            var p = productMap[d.productNo];
            if(!p){
                p = {pmid: d.pmid, qty: d.qty? parseFloat(d.qty): d.qty, unitid: d.unitid, materialList: []};
                productMap[d.productNo] = p;
                b.productList.push(p);
            }
            p.materialList.push({expectmaterialid: d.expectmaterialid, materialid: d.materialid, mark: d.mark})
        }
        for(var i = 0; i < bl.length; i++){
            var b = bl[i];
            if(!(b.productList && b.productList.length)){
                b.productList = [
                    {
                        materialList: [{}]
                    }
                ]
            }
            for(var j = 0; j < b.productList.length; j++){
                var p = b.productList[j];
                if(!(p.materialList && p.materialList.length)){
                    p.materialList = [{}]
                }
            }
        }
        applyBuildingList(bl);
    }

    var validators = {
        "number": function(data){
            if(typeof data == "number"){
                data += "";
            }
            return /^(0|[1-9][0-9]*)(\.[0-9]*)?$/.test(data);
        },
        "txt": function(data){
            return !!data;
        }
    }
    function check(input, fullCheck){
        if(!input || (!input.value && !fullCheck)){
            return true;
        }
        var validator = validators[input.dataset.dataType];
        return validator == null? null: validator(input.value);
    }
    function checkInfo(fullCheck){
        var jqTrs = this.find("tr");
        var infos = [];
        for(var i = 0; i < jqTrs.length; i++){
            var jqThis = $(jqTrs[i]);
            var scopenameInput = jqThis.find(".scopename-input-td").find("input");
            var productQtyInput = jqThis.find(".product-qty-input-td").find("input");
            if(fullCheck){
            	if(scopenameInput.length && !scopenameInput.val()){
            		sys.topmsg("è¯·å¡«åæ¥¼æ ä¿¡æ¯");
            		return false;
            	}
            	if(productQtyInput.length && !iUtils.isFloat(productQtyInput.val(), 2)){
            		sys.topmsg("è¯·å¡«åæ­£ç¡®çå·¥ç¨éä¿¡æ¯ï¼ä¿çä¸¤ä½å°æ°ï¼");
            		return false;
            	}
            }
        }
        return true;
    }

    __jqThis.getBuildingList = getBuildingList;
    __jqThis.render = render;
    __jqThis.toggleMode = toggleMode;
    __jqThis.reset = reset;
    __jqThis.apply = apply;
    __jqThis.applyBuildingList = applyBuildingList;
    __jqThis.applyExcelData = applyExcelData;
    __jqThis.checkInfo = checkInfo;
    __jqThis.utils = {formatList: formatList};
    return __jqThis;
}
})($)